
#include <BHBoxLayout>
#include <BVBoxLayout>
#include <BGridLayout>
#include <BIcon>
#include <BLabel>
#include <BStyle>
#include <BApplication>
#include <BPainter>
#include <BCursor>

#include "OrganizeDialog.h"

OrganizeDialog::OrganizeDialog(BWidget* parent) : BDialog(parent)
{
	this->setSize(500, 500);
	BGridLayout* topLayout = new BGridLayout("top");
	topLayout->setColumnStretch(0, 1);
	topLayout->setColumnStretch(1, 10);
	{
		BLabel* scopeLabel = new BLabel("scope");
		_scopeNameEdit = new BLineEdit();
		_scopeNameEdit->setReadOnly(true);

		BLabel* nameLabel = new BLabel("name");
		_objectNameEdit = new BLineEdit();

		topLayout->setWidget(0, 0, scopeLabel);
		topLayout->setWidget(0, 1, _scopeNameEdit);
		topLayout->setWidget(1, 0, nameLabel);
		topLayout->setWidget(1, 1, _objectNameEdit);
	}
	_infoLabel = new BLabel();
	_listWidget = new BListWidget();
	_nameEdit = new BLineEdit(_listWidget);
	_nameEdit->hide();

	BVBoxLayout* vlayout = new BVBoxLayout(this);
	vlayout->addLayout(topLayout, 0);
	vlayout->addWidget(_infoLabel, 0);
	vlayout->addWidget(_listWidget);
	vlayout->setSpacing(2);

	BHBoxLayout* bottomLayout = new BHBoxLayout(this, Part_Bottom);
	{
		_applyButton = new BButton("Apply");
		_cancelButton = new BButton("Cancel");
		bottomLayout->addSpring();
		bottomLayout->addWidget(_applyButton);
		bottomLayout->addSpacer(10);
		bottomLayout->addWidget(_cancelButton);
	}

	connect(_objectNameEdit, Signal_TextEdited, &OrganizeDialog::slotObjectNameEdited);
	connect(_listWidget, Signal_ItemClicked, &OrganizeDialog::slotListItemClicked);
	connect(_listWidget, Signal_Frame, &OrganizeDialog::slotListWidgetFramed);
	connect(_nameEdit, Signal_Focused, &OrganizeDialog::slotNameEditFocused);
	connect(_applyButton, Signal_Clicked, &OrganizeDialog::slotApplyButtonClicked);
	connect(_cancelButton, Signal_Clicked, &OrganizeDialog::slotCancelButtonClicked);
}
OrganizeDialog::~OrganizeDialog()
{

}

void OrganizeDialog::setTarget(Target* target)
{
	_target = target;
}
Target* OrganizeDialog::target()
{
	return _target;
}

BIcon* OrganizeDialog::iconOf(const BObject* object)
{
	const BStyle* style = this->realStyle();
	for (int i = object->typeCount() - 1; i >= 0; i--)
	{
		const char* type = object->typeName(i);
		if (BIcon* icon = style->icon(type))
		{
			return icon;
		}
	}
	return 0;
}
BImage* OrganizeDialog::imageOf(const BObject* object)
{
	const BStyle* style = this->realStyle();
	for (int i = object->typeCount() - 1; i >= 0; i--)
	{
		const char* type = object->typeName(i);
		if (BIcon* icon = style->icon(type))
		{
			return icon->image();
		}
	}
	return 0;
}

void OrganizeDialog::slotObjectNameEdited(BObject* object, const BValue& value)
{
	const BString& name = value;
	for (int i = 0; i < _listWidget->itemCount(); i++)
	{
		BListItem* item = _listWidget->item(i);
		BObject* obj = item->asset();
		if (obj->name().beginWith(name))
		{
			BString text = obj->name();
			text.remove(name);
			item->setText(text);
			item->setSelected(true);
		}
		else
		{
			item->setText(obj->name());
			item->setSelected(false);
		}
	}
	BString text("checked item count : ");
	text << _listWidget->selectedItemCount() << '/' << _listWidget->itemCount();
	_infoLabel->setText(text);
}
void OrganizeDialog::slotListWidgetFramed(BObject* object, const BValue& value)
{
	BPainter painter((BWidget*)object);
	const BListItemArray& visualItems = _listWidget->query("visual-items");
	for (int i = 0; i < visualItems.size(); i++)
	{
		BListItem* item = visualItems[i];
		BObject* obj = item->asset();
		if (obj->name() != item->text())
		{
			const BRect graphRect = item->iconRect().align(Align_LeftBottom, BSize(12));
			painter.setColor(100, 200, 100);
			painter.drawGraph(graphRect, Graph_Check);
		}
	}
}
void OrganizeDialog::slotListItemClicked(BObject* object, const BValue& value)
{
	if (_nameEdit->asset() != value)
	{
		_nameEdit->setAsset(value);
		_nameEdit->setPos(BCursor::GetPos());
	}
	else
	{
		BListItem* item = value;
		bool editing = (_nameEdit->pos() - BCursor::GetPos()).length2() > 6;
		if (item && editing)
		{
			BRect area = item->textArea();
			BSize ssize = _nameEdit->shellSize();
			BRect rect = area + ssize;
			rect -= BPoint(ssize.width() / 2, ssize.height() / 2);
			if (rect.right() >= _listWidget->centerRect().right())
				rect.right() = _listWidget->centerRect().right() - 1;
			_nameEdit->setParent(_listWidget);
			_nameEdit->setRect(rect);
			_nameEdit->setText(item->text());
			_nameEdit->popup();
		}
	}
}
void OrganizeDialog::slotNameEditFocused(BObject* object, const BValue& value)
{
	if (value == false)
	{
		_nameEdit->hide();
	}
}

void OrganizeDialog::slotApplyButtonClicked(BObject* object, const BValue& value)
{
	BScene* scene = _target->scene();
	if (BGroup* group = this->asset())
	{
		group->setName(_objectNameEdit->text());
		for (int i = 0; i < _listWidget->itemCount(); i++)
		{
			BListItem* item = _listWidget->item(i);
			BObject* obj = item->asset();
			if (item->text() == obj->name())
				continue;
			obj->setName(item->text());
			if (BShape* shape = item->asset())
			{
				group->insert(shape);
				scene->remove(shape);
				continue;
			}
			if (BNode* node = item->asset())
			{
				group->insert(node);
				scene->remove(node);
				continue;
			}
			if (BConstraint* constraint = item->asset())
			{
				group->insert(constraint);
				scene->remove(constraint);
				continue;
			}
			if (BGroup* child = item->asset())
			{
				group->addChild(child);
				scene->remove(child);
				continue;
			}
		}
		if (BGroup* parent = _target->group())
			parent->addChild(group);
		else
			scene->insert(group);
	}
	else if (BNode* node = this->asset())
	{
		node->setName(_objectNameEdit->text());
		for (int i = 0; i < _listWidget->itemCount(); i++)
		{
			BListItem* item = _listWidget->item(i);
			BObject* obj = item->asset();
			if (item->text() == obj->name())
				continue;
			obj->setName(item->text());
			if (BShape* shape = item->asset())
			{
				node->addShape(shape);
				scene->remove(shape);
				continue;
			}
		}
		if (BGroup* parent = _target->group())
			parent->insert(node);
		else
			scene->insert(node);
	}
	this->close(1);
}
void OrganizeDialog::slotCancelButtonClicked(BObject* object, const BValue& value)
{
	this->close(0);
}

void OrganizeDialog::showEvent(const BEvent& event)
{
	BLayout* topLayout = this->layout("top");
	if (BObject* object = this->asset())
	{
		BLabel* label = (BLabel*)topLayout->widget(2);
		label->setImage(imageOf(object));
	}
	if (BGroup* parent = _target->group())
	{
		BLabel* label = (BLabel*)topLayout->widget(0);
		label->setImage(imageOf(parent));
		_scopeNameEdit->setText(parent->name());
		for (int i = 0; i < parent->shapeCount(); i++)
		{
			BShape* shape = parent->shape(i);
			BListItem* item = _listWidget->addItem(shape->name());
			item->setAsset(shape);
		}
		for (int i = 0; i < parent->nodeCount(); i++)
		{
			BNode* node = parent->node(i);
			BListItem* item = _listWidget->addItem(node->name());
			item->setAsset(node);
		}
		for (int i = 0; i < parent->constraintCount(); i++)
		{
			BConstraint* constraint = parent->constraint(i);
			BListItem* item = _listWidget->addItem(constraint->name());
			item->setAsset(constraint);
		}
		for (int i = 0; i < parent->childCount(); i++)
		{
			BGroup* group = parent->child(i);
			BListItem* item = _listWidget->addItem(group->name());
			item->setAsset(group);
		}
	}
	else if (BNode* parent = _target->node())
	{
		BLabel* label = (BLabel*)topLayout->widget(0);
		label->setImage(imageOf(parent));
		_scopeNameEdit->setText(parent->name());
		for (int i = 0; i < parent->shapeCount(); i++)
		{
			BShape* shape = parent->shape(i);
			BListItem* item = _listWidget->addItem(shape->name());
			item->setAsset(shape);
		}
	}
	else if (BScene* parent = _target->scene())
	{
		BLabel* label = (BLabel*)topLayout->widget(0);
		label->setImage(imageOf(parent));
		_scopeNameEdit->setText(parent->name());
		for (int i = 0; i < parent->shapeCount(); i++)
		{
			BShape* shape = parent->shape(i);
			BListItem* item = _listWidget->addItem(shape->name());
			item->setAsset(shape);
		}
		for (int i = 0; i < parent->nodeCount(); i++)
		{
			BNode* node = parent->node(i);
			BListItem* item = _listWidget->addItem(node->name());
			item->setAsset(node);
		}
		for (int i = 0; i < parent->constraintCount(); i++)
		{
			BConstraint* constraint = parent->constraint(i);
			BListItem* item = _listWidget->addItem(constraint->name());
			item->setAsset(constraint);
		}
		for (int i = 0; i < parent->groupCount(); i++)
		{
			BGroup* group = parent->group(i);
			BListItem* item = _listWidget->addItem(group->name());
			item->setAsset(group);
		}
	}
	for (int i = 0; i < _listWidget->itemCount(); i++)
	{
		BListItem* item = _listWidget->item(i);
		item->setIcon(iconOf(item->asset()));
	}
	BDialog::showEvent(event);
}
void OrganizeDialog::hideEvent(const BEvent& event)
{
	_objectNameEdit->setText(BString());
	_infoLabel->setText(BString());
	_listWidget->clearItems();
	BDialog::hideEvent(event);
}
